using System.Linq;
using FireStarter.Base;
using FireStarter.Base.BusinessObjectMerger;
using FireStarterModeller.BO;
using FireStarterModeller.Logic.MergeBusinessObjects;
using FireStarterModeller.Test.BO;
using Habanero.Testability;
using NUnit.Framework;
using TestabilityExtensions = Habanero.Testability.TestabilityExtensions;

namespace FireStarterModeller.Test.Logic.MergeBusinessObjects
{
    [TestFixture]
    public class TestMergeUIForm
    {
        [TestFixtureSetUp]
        public virtual void TestFixtureSetup()
        {
            TestUtilsLogic.SetupFixture();
        }
        [SetUp]
        public virtual void SetupTest()
        {
            TestUtilsLogic.SetupTest();
        }

        [Test]
        public void Test_MergeUIForm_ShouldMergeUITabs()
        {
            //---------------Set up test pack-------------------
            var uiTabMerger = MergeableBORegistry.Instance.Resolve<UIFormInfo>();
            var fromUIForm = TestUtilsUIFormInfo.GetFactory()
                .WithMany(columnLayout => columnLayout.UITabs)
                .WithOutSingleRelationships()
                .CreateValidBusinessObject();
            var uiTabs = fromUIForm.UITabs;
            SetOrdinalPos(uiTabs[0]);
            SetOrdinalPos(uiTabs[1]);
            SetOrdinalPos(uiTabs[2]);
            var toUIForm = new UIFormInfo();
            //---------------Assert Precondition----------------
            Assert.Greater(fromUIForm.UITabs.Count, 2);
            Assert.AreEqual(0, toUIForm.UITabs.Count);
            //---------------Execute Test ----------------------
            uiTabMerger.MergeBOFrom(fromUIForm, toUIForm);
            //---------------Test Result -----------------------
            Assert.AreEqual(fromUIForm.UITabs.Count, toUIForm.UITabs.Count);
        }

        [Test]
        public void Test_MergeUIForm_WhenTwoUpdatedFields_ShouldUpdateFields()
        {
            //---------------Set up test pack-------------------
            var uiTabMerger = MergeableBORegistry.Instance.Resolve<UIFormInfo>();
            var fromUIForm = TestUtilsUIFormInfo.GetFactory()
                .WithTwo(columnLayout => columnLayout.UITabs)
                .WithOutSingleRelationships()
                .CreateValidBusinessObject();
            var uiTabs = fromUIForm.UITabs;
            var fromUITab = uiTabs[0];
            SetOrdinalPos(fromUITab);
            var fromUITab2 = uiTabs[1];
            SetOrdinalPos(fromUITab2);

            var toUIForm = new UIFormInfo ();
            UITab expectedToUITab = AddCopiedUITab(toUIForm, fromUITab);
            UITab expectedToUITab2 = AddCopiedUITab(toUIForm, fromUITab2);

            //---------------Assert Precondition----------------
            Assert.AreEqual(2, fromUIForm.UITabs.Count);
            Assert.AreEqual(fromUITab.Name, expectedToUITab.Name);
            Assert.AreEqual(fromUITab.ToString(), expectedToUITab.ToString());
            Assert.AreNotEqual(fromUITab.OrdinalPosition, expectedToUITab.OrdinalPosition);
            Assert.AreEqual(fromUITab2.Name, expectedToUITab2.Name);
            Assert.AreNotEqual(fromUITab2.OrdinalPosition, expectedToUITab2.OrdinalPosition);
            Assert.AreEqual(fromUITab2.ToString(), expectedToUITab2.ToString());
            //---------------Execute Test ----------------------
            uiTabMerger.MergeBOFrom(fromUIForm, toUIForm);
            //---------------Test Result -----------------------
            Assert.IsNotNull(toUIForm);
            Assert.AreEqual(2, toUIForm.UITabs.Count);
            var toUITab = toUIForm.UITabs.First();
            Assert.AreEqual(fromUITab.Name, toUITab.Name);
            Assert.AreEqual(fromUITab.OrdinalPosition, toUITab.OrdinalPosition);
            var toUITab2 = toUIForm.UITabs.Last();
            Assert.AreEqual(fromUITab2.Name, toUITab2.Name);
            Assert.AreEqual(fromUITab2.OrdinalPosition, toUITab2.OrdinalPosition);
        }

        private static void SetOrdinalPos(UITab uiTab)
        {
            uiTab.OrdinalPosition = GetValidOrdinalPos(uiTab);
        }

        private static int? GetValidOrdinalPos(UITab uiTab)
        {
            return GetFactory().GetValidPropValue(uiTab, layout => layout.OrdinalPosition);
        }

        private static BOTestFactory<UITab> GetFactory()
        {
            return TestUtilsUITab.GetFactory();
        }
        [Test]
        public void Test_MergeUIForm_WhenOneRemovedUiField_ShouldUpdateFieldStatusToDelete()
        {
            //---------------Set up test pack-------------------
            var uiTabMerger = MergeableBORegistry.Instance.Resolve<UIFormInfo>();
            var fromUIForm = new UIFormInfo();
            var fromUITab = CreateUITab(fromUIForm);
            var fromUITab2 = CreateUITab(fromUIForm);
            var toUIForm = new UIFormInfo();
            UITab expectedToUITab = AddCopiedUITab(toUIForm, fromUITab);
            UITab expectedToUITab2 = AddCopiedUITab(toUIForm, fromUITab2);
            fromUIForm.UITabs.Remove(fromUITab2);
            //---------------Assert Precondition----------------
            Assert.AreEqual(1, fromUIForm.UITabs.Count);
            Assert.AreEqual(2, toUIForm.UITabs.Count);
            Assert.AreNotEqual(fromUITab.OrdinalPosition, expectedToUITab.OrdinalPosition);
            Assert.AreNotEqual(ChangeType.Update, expectedToUITab.PendingChangeType);
            Assert.AreNotEqual(ChangeType.Delete, expectedToUITab2.PendingChangeType);
            //---------------Execute Test ----------------------
            uiTabMerger.MergeBOFrom(fromUIForm, toUIForm);
            //---------------Test Result -----------------------

            Assert.IsNotNull(toUIForm);
            Assert.AreEqual(2, toUIForm.UITabs.Count);
            var toUITab = toUIForm.UITabs.First();
            Assert.AreSame(toUITab, expectedToUITab);

            var toUITab2 = toUIForm.UITabs.Last();
            Assert.AreSame(toUITab2, expectedToUITab2);
            Assert.AreEqual(ChangeType.Delete, toUITab2.PendingChangeType);
            Assert.AreEqual(ChangeType.None, toUITab.PendingChangeType);
        }

        [Test]
        public void Test_MergeUIForm_WhenMergeToNotNull_ShouldUpdateUIForm()
        {
            //---------------Set up test pack-------------------
            IMergeBO<UIFormInfo> mergeBO = MergeableBORegistry.Instance.Resolve<UIFormInfo>();
            var boTestFactory = TestUtilsUIFormInfo.GetFactory();
            var fromUIForm = TestabilityExtensions.WithValueFor<UIFormInfo, string>(boTestFactory
                                                      .WithOutSingleRelationships(), frm => frm.Title)
                .CreateValidBusinessObject();
            var toUiField = new UIFormInfo();
            //---------------Assert Precondition----------------
            Assert.AreNotEqual(fromUIForm.Title, toUiField.Title);
            //---------------Execute Test ----------------------
            mergeBO.MergeBOFrom(fromUIForm, toUiField);
            //---------------Test Result -----------------------
            Assert.AreEqual(fromUIForm.Title, toUiField.Title);
        }

        private static UITab AddCopiedUITab(UIFormInfo toUIForm, UITab fromUIfield)
        {
            var expectedToUITab = new UITab { Name = fromUIfield.Name };
            expectedToUITab.OrdinalPosition = GetFactory().GetValidPropValue(layout => layout.OrdinalPosition);
            toUIForm.UITabs.Add(expectedToUITab);
            return expectedToUITab;
        }

        private static UITab CreateUITab(UIFormInfo uiFormInfo)
        {
            var uiTab = uiFormInfo.UITabs.CreateBusinessObject();
            uiTab.OrdinalPosition = GetFactory().GetValidPropValue(layout => layout.OrdinalPosition);
            uiTab.Name = GetFactory().GetValidPropValue(layout => layout.Name);
            return uiTab;
        }
    }
}